<template>
	<view class="virtual-list" style="position: relative;">
		<movable-area style="position: absolute;right: 0;width: 30px;height: 100%;">
			<movable-view class="action-bar-box" direction="vertical" @change="change" :y="y" :animation="false">
				<view style="border-bottom: #000 solid 2px;width: 100%;"></view>
				<view style="border-bottom: #000 solid 2px;width: 100%;"></view>
			</movable-view>
		</movable-area>
		<scroll-view
			scroll-y="true"
			:style="{
				height: scrollHeight + 'px',
				position: 'relative',
				zIndex: 1
			}"
			@scroll="handleScroll"
			:scroll-top="scrollTop"
			:show-scrollbar="false"
		>
			<view
				class="scroll-bar"
				:style="{
					height: localHeight + 'px'
				}"
			></view>
			<view
				class="list"
				:style="{
					transform: `translateY(${offset}px)`
				}"
			>
				<view class="item-wrap" v-for="(item, index) in visibleData" :key="index"><slot :item="item" :active="active"></slot></view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
export default {
	name: 'VirtualList',
	props: {
		// 所有的items
		items: Array,
		// 可视区域的item数量
		remain: Number,
		// item大小
		size: Number,
		// 当前章节
		active: Number,
		// 可使区域高度
		scrollHeight: Number
	},
	data() {
		return {
			// 起始
			start: 0,
			// 结束
			end: this.remain,
			// list 偏移量
			offset: 0,
			scrollTop: 0,
			y: 0
		};
	},
	created() {
		//当前章节滚动至顶部
		this.scrollTop = this.size * this.active;
	},
	computed: {
		// 预留项
		preCount() {
			return Math.min(this.start, this.remain);
		},
		nextCount() {
			return Math.min(this.items.length - this.end, this.remain);
		},
		// 可视区域的item
		visibleData() {
			const start = this.start - this.preCount;
			const end = this.end + this.nextCount;
			return this.items.slice(start, end);
		},
		localHeight() {
			return this.items.length * this.size;
		}
	},
	methods: {
		change(e) {
			if (e.detail.source !== 'touch') {
				return;
			}
			let y = e.detail.y;
			let scroll = (y / (this.scrollHeight - 40)) * (this.localHeight - this.scrollHeight);
			scroll = scroll < 0 ? 0 : scroll;
			this.scrollTop = scroll;
		},
		handleScroll(ev) {
			const scrollTop = ev.detail.scrollTop;
			this.y = (scrollTop / (this.localHeight - this.scrollHeight)) * (this.scrollHeight - 40);
			// 开始位置
			const start = Math.floor(scrollTop / this.size);
			this.start = start < 0 ? 0 : start;
			// 结束位置
			this.end = this.start + this.remain;
			// 计算偏移
			const offset = scrollTop - (scrollTop % this.size) - this.preCount * this.size;
			this.offset = offset < 0 ? 0 : offset;
		}
	}
};
</script>

<style scoped>
.list {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
}
.action-bar-box {
	padding: 3px;
	display: flex;
	flex-flow: column;
	justify-content: space-around;
	align-items: center;
	position: absolute;
	right: 0;
	background-color: transparent;
	border-radius: 10rpx;
	box-shadow: 0 0 5px #000;
	width: 20px;
	height: 40px;
	z-index: 2;
}
</style>
